fix(fair2): idealised conc-driven PI ERF + empty-bundle splice#105
Closed
benmsanderson wants to merge 5 commits into
Closed
Conversation
Idealised scenarios (abrupt-4xCO2, 1pctCO2, esm-flat10*) have no RCMIP3 emissions baseline, so _rcmip3_to_fair_emissions_df returns an empty, column-less DataFrame. When the user also supplies Emissions|* rows, _splice_bundle_with_user hit `KeyError: 'scenario'` at bundle_df["scenario"].isin(...) — the existing `if spliced_df.empty` fallback is unreachable because the KeyError fires first, and the caller build_emissions_df only short-circuits the all-empty case. Short-circuit to the user's rows when the bundle is empty. They still flow through build_emissions_df's co2_only_scenarios zeroing and the year-column stringify, so idealised treatment is preserved. Adds two unit regressions (no FaIR run): the direct empty-bundle splice, and an end-to-end build_emissions_df for an idealised scenario with a user overlay asserting CO2 survives and non-CO2 is zeroed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Idealised experiments (abrupt-4xCO2, 1pctCO2, esm-flat10*) hold everything but CO2 at pre-industrial. The adapter previously left the non-CO2 emissions-mode species at *zero* emissions (the co2_only zeroing in build_emissions_df and the _zero_fill_fair_arrays safety net). But FaIR evaluates emissions-driven forcing -- aerosols in particular -- relative to each species' baseline_emissions, so zero emissions is NOT the PI reference: it leaves a constant spurious ERF (anomaly 0 - baseline_emissions). Decomposed on an abrupt-4xCO2 conc-driven run (mini calibration): the non-CO2 ERF residual is +0.41 W/m^2 at the PI branch point, dominated by aerosols (+0.64 W/m^2). With the AR7 1.4.1 calibration this is the reported +1.53 W/m^2. Fix: after the fills, pin non-CO2 emissions-mode species to baseline_emissions for idealised scenarios (CO2 sources excluded -- they are concentration-driven / back-calculated). This makes the anomaly, and hence the PI forcing, ~0. Verified: non-CO2 ERF +0.41 -> +0.001 at 1850; aerosols +0.64 -> +0.003; CH4 -> 0.000. Non-idealised runs are untouched (the existing ssp245 modern-adapter snapshots are unchanged). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Document how each adapter treats the non-concentration-driven species (aerosol / ozone precursors and any GHG not supplied as a concentration) in conc-driven runs, and how that differs for idealised experiments (abrupt-4xCO2, 1pctCO2, esm-flat10*): - MAGICC7 requires explicit Emissions|* for those species (no idealised auto-detection), - FaIR2 zeroes natural/land-use forcing and holds non-CO2 emissions-mode species at baseline_emissions for idealised scenarios, - CICEROSCMPY2 zeroes unsupplied emissions / holds unsupplied concentrations at PI. Recommends supplying the esm-piControl emissions overlay explicitly for reproducible cross-model idealised runs (the only way to get correct PI behaviour from MAGICC7). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Regression guard for the idealised baseline fix: drive abrupt-4xCO2 by CO2 concentration only and assert the non-CO2 ERF (total minus CO2) at the 1850 branch point is ~0. Before the fix this carried a constant ~+0.6 W/m^2 aerosol offset (the +1.53 W/m^2 PI residual with the AR7 1.4.1 calibration). Env-gated on the full RCMIP3 bundle (the mini fixture lacks abrupt-4xCO2 concentrations); FaIR2-only because MAGICC7 needs an explicit esm-piControl overlay for idealised runs and CICEROSCMPY2 exposes only component-wise ERF (cross-adapter assertion is a follow-up). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Collaborator
Author
|
Superseded by #106 (same diff, pushed in-repo so CI can access the MAGICC download secret — fork PRs don't get repo secrets, which is why the MAGICC-download step failed here). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Fixes the two FaIR2 idealised-experiment issues surfaced while wiring the AR7 WG1 Ch5 ensemble onto the conc-driven adapters, plus docs and a regression test. Stacked on
feat/fair2-ciceroscmpy2-adapters-and-runmode-nonfork.Issue 1 —
_splice_bundle_with_userKeyError on empty bundleIdealised scenarios (
abrupt-4xCO2,1pctCO2,esm-flat10*) have no RCMIP3 emissions baseline, so_rcmip3_to_fair_emissions_dfreturns an empty, column-less frame. When the user also suppliedEmissions|*rows,_splice_bundle_with_userhitKeyError: 'scenario'atbundle_df["scenario"].isin(...)(theif spliced_df.emptyfallback is unreachable — the KeyError fires first). Short-circuit to the user's rows when the bundle is empty. Two unit regressions added (no FaIR run).Issue 2 — +1.53 W/m² preindustrial ERF residual
Decomposed the residual on an
abrupt-4xCO2conc-driven run: it is a constant aerosol ERF offset (+0.64 W/m² in the mini calibration; +1.53 with the AR7 1.4.1 calibration), not leaking non-CO2 emissions.Root cause: FaIR evaluates emissions-driven forcing (aerosols especially) relative to each species'
baseline_emissions. The idealised path left non-CO2 species at zero emissions (theco2_onlyzeroing /_zero_fill_fair_arrays), so the anomaly was0 − baseline_emissions→ a constant spurious forcing. Zero emissions is not the PI reference.Fix: for idealised scenarios, pin non-CO2 emissions-mode species to
baseline_emissions(CO2 sources excluded — they are concentration-driven). The anomaly, and hence the PI forcing, becomes ~0.Verified (mini calibration, abrupt-4xCO2 conc-driven), non-CO2 ERF at the 1850 branch point:
Non-idealised runs are untouched — the existing ssp245 modern-adapter snapshots are unchanged.
Docs
New "Idealised experiments and the non-conc-species baseline" page documenting how each adapter (MAGICC7 / FaIR2 / CICEROSCMPY2) treats non-conc species in conc-driven runs, and recommending the explicit
esm-piControlemissions overlay for reproducible cross-model idealised runs.Tests
test_rcmip3.py: empty-bundle splice + end-to-endbuild_emissions_dffor an idealised scenario with a user overlay (CO2 survives, non-CO2 zeroed).test_idealised_pi_erf.py: FaIR2 idealised non-CO2 ERF ~0 at the PI branch point (env-gated on the full RCMIP3 bundle).Notes / follow-ups
esm-piControloverlay for idealised runs (no auto-detection); CICEROSCMPY2 exposes only component-wise ERF (no plain total/CO2 pair). A true cross-adapter assertion is a follow-up.🤖 Generated with Claude Code